package com.stable.actor.core;

import lombok.extern.slf4j.Slf4j;

import java.util.ArrayList;
import java.util.List;
import java.util.Optional;

/**
 * Actor上下文，提供运行时环境信息
 */
@Slf4j
public class ActorContext {

    private final ActorSystem system;
    private final ActorRef self;
    private final ActorRef sender;
    private final List<ActorRef> watchedActors = new ArrayList<>();

    public ActorContext(ActorSystem system, ActorRef self, ActorRef sender) {
        this.system = system;
        this.self = self;
        this.sender = sender;
    }

    public ActorSystem getSystem() {
        return system;
    }

    public ActorRef getSelf() {
        return self;
    }

    public ActorRef getSender() {
        return sender;
    }

    public void reply(Object message) {
        if (sender != null) {
            sender.send(message);
        }
    }

    /**
     * 创建子 Actor
     */
    public ActorRef actorOf(Props props, String name) {
        String fullPath = self.path() + "/" + name;

        // 使用 ActorSystem 的 actorOf 方法，它支持 Props
        ActorRef childActor = system.actorOf(props, name);

        // 自动监控子 Actor
        watch(childActor);

        return childActor;
    }

    /**
     * 创建子 Actor（使用类名）
     */
    public ActorRef createChild(String name, Class<? extends StableActor> actorClass) {
        Props props = Props.create(actorClass);
        return actorOf(props, name);
    }

    /**
     * 查找指定路径的 Actor
     *
     * @param actorPath Actor的路径，可以是绝对路径或相对路径
     * @return 如果找到则返回ActorRef的Optional，否则返回空的Optional
     */
    public Optional<ActorRef> findActor(String actorPath) {
        if (actorPath == null || actorPath.trim().isEmpty()) {
            warn("查找Actor路径不能为空");
            return Optional.empty();
        }

        try {
            // 处理相对路径
            String absolutePath;
            if (actorPath.startsWith("/")) {
                // 绝对路径
                absolutePath = actorPath;
            } else {
                // 相对路径，相对于当前Actor的路径
                absolutePath = self.path() + "/" + actorPath;
            }

            ActorRef foundActor = system.findActor(absolutePath);
            if (foundActor != null) {
                debug("找到Actor: {}", absolutePath);
                return Optional.of(foundActor);
            } else {
                debug("未找到Actor: {}", absolutePath);
                return Optional.empty();
            }
        } catch (Exception e) {
            error("查找Actor时发生错误: {}, 路径: {}", e.getMessage(), actorPath);
            return Optional.empty();
        }
    }

    /**
     * 查找指定名称的Actor（在当前Actor的子Actor中查找）
     *
     * @param actorName Actor名称
     * @return 如果找到则返回ActorRef的Optional，否则返回空的Optional
     */
    public Optional<ActorRef> findChildActor(String actorName) {
        if (actorName == null || actorName.trim().isEmpty()) {
            warn("查找子Actor名称不能为空");
            return Optional.empty();
        }

        String childPath = self.path() + "/" + actorName;
        return findActor(childPath);
    }

    /**
     * 查找指定名称的Actor，如果不存在则创建
     *
     * @param actorName Actor名称
     * @param actorClass Actor类
     * @return 找到或创建的ActorRef
     */
    public ActorRef findOrCreateChild(String actorName, Class<? extends StableActor> actorClass) {
        Optional<ActorRef> existingActor = findChildActor(actorName);
        if (existingActor.isPresent()) {
            return existingActor.get();
        } else {
            info("创建子Actor: {}", actorName);
            return createChild(actorName, actorClass);
        }
    }

    /**
     * 查找指定名称的Actor，如果不存在则使用Props创建
     *
     * @param actorName Actor名称
     * @param props Actor属性
     * @return 找到或创建的ActorRef
     */
    public ActorRef findOrCreateChild(String actorName, Props props) {
        Optional<ActorRef> existingActor = findChildActor(actorName);
        if (existingActor.isPresent()) {
            return existingActor.get();
        } else {
            info("创建子Actor: {}", actorName);
            return actorOf(props, actorName);
        }
    }

    /**
     * 监控指定的 Actor，当该 Actor 终止时会收到 Terminated 消息
     */
    public void watch(ActorRef subject) {
        if (subject == null) {
            throw new IllegalArgumentException("Subject actor cannot be null");
        }

        if (subject.equals(self)) {
            log.warn("Actor cannot watch itself: {}", self.path());
            return;
        }

        if (!watchedActors.contains(subject)) {
            watchedActors.add(subject);
            system.watch(subject, self);
            log.debug("Actor {} started watching {}", self.path(), subject.path());
        }
    }

    /**
     * 取消监控指定的 Actor
     */
    public void unwatch(ActorRef subject) {
        if (subject == null) {
            throw new IllegalArgumentException("Subject actor cannot be null");
        }

        if (watchedActors.remove(subject)) {
            system.unwatch(subject, self);
            log.debug("Actor {} stopped watching {}", self.path(), subject.path());
        }
    }

    /**
     * 停止指定的 Actor
     */
    public void stop(ActorRef actor) {
        if (actor != null) {
            system.stopActor(actor.path());
        }
    }

    /**
     * 停止自身
     */
    public void stop() {
        system.stopActor(self.path());
    }

    /**
     * 获取当前监控的所有 Actor
     */
    public List<ActorRef> getWatchedActors() {
        return new ArrayList<>(watchedActors);
    }

    /**
     * 清理监控列表（在 Actor 停止时调用）
     */
    public void clearWatchers() {
        for (ActorRef watched : watchedActors) {
            system.unwatch(watched, self);
        }
        watchedActors.clear();
    }

    public void info(String format, Object... args) {
        log.info("[{}] {}", self.path(), String.format(format, args));
    }

    public void warn(String format, Object... args) {
        log.warn("[{}] {}", self.path(), String.format(format, args));
    }

    public void error(String format, Object... args) {
        log.error("[{}] {}", self.path(), String.format(format, args));
    }

    /**
     * 调试日志
     */
    public void debug(String format, Object... args) {
        log.debug("[{}] {}", self.path(), String.format(format, args));
    }
}
